package subumbo.audio.effect
{
	import __AS3__.vec.Vector;
	
	import flash.utils.setTimeout;
	
	import subumbo.audio.core.IAudioProcessor;
	import subumbo.audio.driver.AudioDriver;	

	/**
	 * Simple delay line with a static read offset (max: size of delay line - 1)
	 * 
	 * @author Andre Michelle
	 */
	public class SimpleDelay
		implements IAudioProcessor 
	{
		private var _id:String;
		private const delaySize: int = ( 1000 * 44.1 ); // max 1000ms @44.1KHz
		private const delayLine: Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>( 2, true );
		
		private var _delayOffset: int;
		private var _wetLevel: Number;
		private var _feedback: Number;
		
		private var _writeIndex: int;
		
		private var _deactivatedFunction:Function;
		private var _activateFucntion:Function;
		
		private var _processIndex:int;
		
		private var _activated:Boolean;
		private var _genID:String;
		
		private var _vL:Number = 1;
		private var _vR:Number = 1;
		
		public function SimpleDelay( id:String, delayOffset: int, wetLevel: Number, feedback: Number )
		{
			_id = id;
			if( delayOffset >= delaySize )
				throw new RangeError();
			
			_delayOffset = delayOffset;
			_wetLevel = wetLevel;
			_feedback = feedback;
			
			delayLine[0] = new Vector.<Number>( delaySize, true );
			delayLine[1] = new Vector.<Number>( delaySize, true );
			
			_writeIndex = 0;
		}

		public function process( buffer: Vector.<Vector.<Number>> ): void
		{
			var leDelayLine: Vector.<Number> = delayLine[0];
			var riDelayLine: Vector.<Number> = delayLine[1];

			var leBuffer: Vector.<Number> = buffer[0];
			var riBuffer: Vector.<Number> = buffer[1];
			
			var readIndex: int;
			
			var i: int = 0;
			var n: int = AudioDriver.SIZE;
			
			if(_activated)
			{
				for( ; i < n ; ++i )
				{
					//-- read at the end of the delay line
					readIndex = _writeIndex - _delayOffset;
					
					//-- clamp
					if( readIndex < 0 )
						readIndex += delaySize;
						
					//-- write input to delay line (replace)
					leDelayLine[ _writeIndex ] = leBuffer[i];
					riDelayLine[ _writeIndex ] = riBuffer[i];
					
					//-- write read feedback to delay line (add)
					leDelayLine[ _writeIndex ] += leDelayLine[ readIndex ] * _feedback;
					leDelayLine[ _writeIndex ] += riDelayLine[ readIndex ] * _feedback;
	
					//-- write read amplitudes into buffer (add > dry level = 1.0)
					leBuffer[i] += leDelayLine[ readIndex ] * _wetLevel;
					riBuffer[i] += riDelayLine[ readIndex ] * _wetLevel;
					
					//-- move write head
					if( ++_writeIndex == delaySize )
						_writeIndex = 0;
				}
			}else
			{
				i = AudioDriver.SIZE;
						while( --i > -1 )
						{
							leBuffer[i] = 0.0 ;
							riBuffer[i] = 0.0;
						}
			}
		}
		
		public function set volume(val:Number):void
		{
			
		}
		
		public function deactivate():void
		{
			_activated = false;
			setTimeout(deactivated, 140);
		}
		
		private function deactivated():void
		{
			_deactivatedFunction.call(null, this);
		}
		
		public function set deactivatedFunction(val:Function):void
		{
			_deactivatedFunction = val;
		}
		
		public function activate():void
		{
			_activateFucntion.call(null, _id)
			_activated = true
		}
		
		public function set activateFunction(val:Function):void
		{
			_activateFucntion = val;
		}
		
		
		
		public function set addEffectFunction(val:Function):void
		{
			
		}
		public function set removeEffectFunction(val:Function):void
		{
			
		}
		
		public function addEffect(effect:IAudioProcessor):IAudioProcessor
		{
			return effect;
		}
		
		public function removeEffect(obj:Object):void
		{
			return;
		}
		
		public function get id():String
		{
			return _id;
		}
		
		public function set id(val:String):void
		{
			_id = val;
		}
		
		public function setActivated(boo:Boolean):void
		{
			_activated = boo;
		}
		
		public function set generatorID(val:String):void
		{
			_genID = val;
		}
		
		public function get generatorID():String
		{
			return _genID;
		}
		
		public function get activated():Boolean
		{
			return _activated;
		}
		
		public function flush():void
		{
			
		}
		
		public function set processIndex(val:int):void
		{
			_processIndex = val;
		}
		
		public function get processIndex():int
		{
			return _processIndex;
		}
	}
}
